#ifndef CRECIPEFILTER_H
#define CRECIPEFILTER_H

#include <QObject>
#include <QMap>
#include "cconstdefinition.h"

namespace cooking {

class CNutritionFilter;
class CRecipeFilter : public QObject
{
    Q_OBJECT
    Q_ENUMS(EMoreLessType)
    Q_ENUMS(EFilterType)
public:
    explicit CRecipeFilter(QObject *parent = 0);
    CRecipeFilter(const CRecipeFilter& other);
    CRecipeFilter& operator =(const CRecipeFilter& other);
    bool operator ==(const CRecipeFilter& other);
    bool operator !=(const CRecipeFilter& other);
    enum EFilterType{
        /**
         * Must have
         */
        EInclude,
        /**
         * Must not have
         */
        EExclude,
        /**
         * May have
         */
        EMay
    };

    enum EMoreLessType {
        EMore,
        ELess,
        EEqual,
        ENotEqual,
        ELessOrEqual,
        EMoreOrEqual
    };

    /**
     * Add or modify ingredient, add if not exist or replace if exist
     * @param ingredientId Ingredient id
     * @param filterType Filter type
     * @return KOk for ok or KInvalidId if id could not be found
     */
    Q_INVOKABLE int addIngredient(int ingredientId, EFilterType filterType);

    /**
     * Delete ingredient
     * @param ingredientId Ingredient id
     */
    Q_INVOKABLE void deleteIngredient(int ingredientId);

    /**
     * Get ingredient filters
     * @param filterType Filter type
     * @return Filters list that were added
     */
    Q_INVOKABLE QList<int> ingredients(EFilterType filterType);

    /**
     * Add exist ingredient
     * @param ingredientId Ingredient id
     * @return KOk for ok or KInvalidId if id could not be found
     */
    Q_INVOKABLE int addExistIngredient(int ingredientId);

    /**
     * Delete exist ingredient
     * @param ingredientId Ingredient id
     */
    Q_INVOKABLE void deleteExistIngredient(int ingredientId);

    /**
     * Get exist ingredients
     * @return Exist ingredient list that were added
     */
    Q_INVOKABLE QList<int> existIngredients();

    /**
     * Add or modify cuisine, add if not exist or replace if exist
     * @param cuisineId Cuisine id
     * @param filterType Filter type
     * @return KOk for ok or KInvalidId if id could not be found
     */
    Q_INVOKABLE int addCuisine(int cuisineId, EFilterType filterType);

    /**
     * Delete cuisine
     * @param cuisineId Cuisine id
     */
    Q_INVOKABLE void deleteCuisine(int cuisineId);

    /**
     * Get cuisine filters
     * @param filterType Filter type
     * @return Filters list that were added
     */
    Q_INVOKABLE QList<int> cuisines(EFilterType filterType);

    /**
     * Add or modify technique, add if not exist or replace if exist
     * @param techniqueId Technique id
     * @param filterType Filter type
     * @return KOk for ok or KInvalidId if id could not be found
     */
    Q_INVOKABLE int addTechnique(int techniqueId, EFilterType filterType);
    /**
     * Delete technique
     * @param techniqueId Technique id
     */
    Q_INVOKABLE void deleteTechnique(int techniqueId);

    /**
     * Get technique filters
     * @param filterType Filter type
     * @return Filters list that were added
     */
    Q_INVOKABLE QList<int> techniques(EFilterType filterType);

    /**
     * Add or modify flavour, add if not exist or replace if exist
     * @param flavourId Flavour id
     * @param filterType Filter type
     * @return KOk for ok or KInvalidId if id could not be found
     */
    Q_INVOKABLE int addFlavour(int flavourId, EFilterType filterType);
    /**
     * Delete flavour
     * @param flavourId Flavour id
     */
    Q_INVOKABLE void deleteFlavour(int flavourId);

    /**
     * Get flavour filters
     * @param filterType Filter type
     * @return Filters list that were added
     */
    Q_INVOKABLE QList<int> flavours(EFilterType filterType);

    /**
     * Add or modify dish type, add if not exist or replace if exist
     * @param dishTypeId Dish type id
     * @param filterType Filter type
     * @return KOk for ok or KInvalidId if id could not be found
     */
    Q_INVOKABLE int addDishType(int dishTypeId, EFilterType filterType);
    /**
     * Delete dish type
     * @param dishTypeId Dish type id
     */
    Q_INVOKABLE void deleteDishType(int dishTypeId);

    /**
     * Get dish type filters
     * @param filterType Filter type
     * @return Filters list that were added
     */
    Q_INVOKABLE QList<int> dishTypes(EFilterType filterType);

    /**
     * Add or modify food type, add if not exist or replace if exist
     * @param foodTypeId Food type id
     * @param filterType Filter type
     * @return KOk for ok or KInvalidId if id could not be found
     */
    Q_INVOKABLE int addFoodType(int foodTypeId, EFilterType filterType);
    /**
     * Delete food type
     * @param foodTypeId Food type id
     */
    Q_INVOKABLE void deleteFoodType(int foodTypeId);

    /**
     * Get food type filters
     * @param filterType Filter type
     * @return Filters list that were added
     */
    Q_INVOKABLE QList<int> foodTypes(EFilterType filterType);

    /**
     * Add or modify time, add if type is not exist or replace if exist
     * Note: if moreLessType is not EEqual and EEqual type time is exist,
     * the EEqual type time is removed
     * @param time Time
     * @param moreLessType Moreless type
     * @return KOk for ok or KInvalidId if id could not be found
     */
    Q_INVOKABLE int addReadyTime(int time, EMoreLessType moreLessType);
    /**
     * Delete ready time
     * @param type Ready time type
     */
    Q_INVOKABLE void deleteReadyTime(EMoreLessType type);

    /**
     * Get ready times filters
     * @param moreLessType More less type
     * @return Ready time, KInvalidId for invalid
     */
    Q_INVOKABLE int readyTimes(EMoreLessType moreLessType);

    /**
     * Add or modify nutrition, add if not exist or replace if exist
     * @param nutritionId Nutrition id
     * @param moreLessType Moreless type
     * @param quantity Nutrition quantity, use unit type of nutrition table
     * @return KOk for ok or KInvalidId if id could not be found
     */
    Q_INVOKABLE int addNutrition(int nutritionId, EMoreLessType moreLessType,
                                 double quantity);
    /**
     * Delete nutrition
     * @param nutritionId Nutrition id
     */
    Q_INVOKABLE void deleteNutrition(int nutritionId);

    /**
     * Get nutritions filters
     * @return Filters list that were added
     */
    Q_INVOKABLE QList<CNutritionFilter> nutritions();

private: //Ingredient category is used at this moment
    /**
     * Add or modify ingredient category, add if not exist or replace if exist
     * @param categoryId Ingredient category id
     * @param filterType Filter type
     * @return KOk for ok or KInvalidId if id could not be found
     */
    Q_INVOKABLE int addIngredientCategory(int categoryId, EFilterType filterType);
    /**
     * Delete ingredient category
     * @param categoryId Ingredient category id
     */
    Q_INVOKABLE void deleteIngredientCategory(int categoryId);

    /**
     * Get ingredient category filters
     * @param filterType Filter type
     * @return Filters list that were added
     */
    Q_INVOKABLE QList<int> ingredientCategory(EFilterType filterType);

signals:

public slots:

private:
    QMap<int, EFilterType>::iterator addFilter(QMap<int, EFilterType> & filterMap,
                  int filterId, EFilterType &filterType);
    QMap<int, EMoreLessType>::iterator addFilter(QMap<int, EMoreLessType> & filterMap,
                  int filterId, EMoreLessType &filterType);
    QMap<int, CNutritionFilter>::iterator
                  addFilter(QMap<int, CNutritionFilter> & filterMap,
                  int filterId, CNutritionFilter &filter);

    int deleteFilter(QMap<int, EFilterType> & filterMap,
                      int filterId);
    int deleteFilter(QMap<int, EMoreLessType> & filterMap,
                      int filterId);
    int deleteFilter(QMap<int, EMoreLessType> & filterMap,
                      EMoreLessType filterType);
    int deleteFilter(QMap<int, CNutritionFilter> & filterMap,
                      int filterId);


    QList<int> filters(QMap<int, EFilterType> & filterMap,
                 EFilterType filterType);
    QList<int> filters(QMap<int, EMoreLessType> & filterMap,
                 EMoreLessType moreLessType);
    QList<CNutritionFilter>
               filters(QMap<int, CNutritionFilter> & filterMap);

    void copy(const CRecipeFilter& other);

private:
    QList<int> m_exist_ingredient;
    QMap<int, EFilterType> m_ingredient;
    QMap<int, EFilterType> m_cuisine;
    QMap<int, EFilterType> m_technique;
    QMap<int, EFilterType> m_flavour;
    QMap<int, EFilterType> m_dish_type;
    QMap<int, EFilterType> m_food_type;
    QMap<int, EFilterType> m_ingredient_category;
    QMap<int, EMoreLessType> m_ready_time;
    QMap<int, CNutritionFilter> m_nutrition;

    friend class CRecipeModel;
};

class CNutritionFilter: public QObject {
    Q_OBJECT

    Q_ENUMS(ERecipeFilterType)
    Q_PROPERTY(int nutritionId READ nutritionId WRITE setNutritionId)
    //Don't know why need to add cooking:: to moreLess if namespace is used
    //or the compile always fails
    Q_PROPERTY(cooking::CRecipeFilter::EMoreLessType moreLess READ moreLess WRITE setMoreLess)
    Q_PROPERTY(double quantity READ quantity WRITE setQuantity)
    Q_PROPERTY(ERecipeFilterType recipeFilterType READ recipeFilterType WRITE setRecipeFilterType)
public:
    enum ERecipeFilterType {
        EPerServe, //Per serve
        EPerRecipe //Per recipe
    };

    CNutritionFilter();
    CNutritionFilter(const CNutritionFilter& other);
    CNutritionFilter& operator=(const CNutritionFilter& other);
    bool operator==(const CNutritionFilter& other) const;

    int nutritionId();
    void setNutritionId(int nutritionId);

    CRecipeFilter::EMoreLessType moreLess();
    void setMoreLess(CRecipeFilter::EMoreLessType moreLess);

    double quantity();
    void setQuantity(double quantity);

    ERecipeFilterType recipeFilterType();
    void setRecipeFilterType(ERecipeFilterType recipeFilterType);

private:
    int m_nutrition_id;
    CRecipeFilter::EMoreLessType m_more_less;
    double m_quantity;
    static ERecipeFilterType s_recipe_filter_type;
};
} // namespace cooking
#endif // CRECIPEFILTER_H
